package com.such.kit.validate;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
import com.such.kit.Callable;
import com.such.kit.Logger;
import com.such.kit.bean.BeanCommons;
import com.such.kit.cache.CacheCommons;
import com.such.kit.validate.exception.VerifyException;
import com.such.kit.validate.validator.Validator;
import com.such.kit.validate.validator.bean.VerifyResult;
import com.such.kit.validate.validator.exception.ValidatorNotFoundException;

/**
 * @author SUCH
 * <pre>
 * 通用的校验工具类
 * </pre>
 */
public class ValidateCommons {

	/** VALIDATOR_LENGTH：[参考 {@link com.such.kit.validate.validator.impl.LengthValidator}] */
	public static final String VALIDATOR_LENGTH = "com.such.kit.validate.validator.impl.LengthValidator";
	/** VALIDATOR_LENGTH_RANGE：[参考 {@link com.such.kit.validate.validator.impl.LengthRangeValidator}] */
	public static final String VALIDATOR_LENGTH_RANGE = "com.such.kit.validate.validator.impl.LengthRangeValidator";
	/** VALIDATOR_DATA_RANGE：[参考 {@link com.such.kit.validate.validator.impl.DataRangeValidator}] */
	public static final String VALIDATOR_DATA_RANGE = "com.such.kit.validate.validator.impl.DataRangeValidator";
	/** VALIDATOR_MATCH：[参考 {@link com.such.kit.validate.validator.impl.MatchValidator}] */
	public static final String VALIDATOR_MATCH = "com.such.kit.validate.validator.impl.MatchValidator";
	/** VALIDATOR_UNMATCH：[参考 {@link com.such.kit.validate.validator.impl.UnmatchValidator}] */
	public static final String VALIDATOR_UNMATCH = "com.such.kit.validate.validator.impl.UnmatchValidator";
	/** VALIDATOR_EMPTY：[参考 {@link com.such.kit.validate.validator.impl.EmptyValidator}] */
	public static final String VALIDATOR_EMPTY = "com.such.kit.validate.validator.impl.EmptyValidator";
	/** VALIDATOR_UNEMPTY：[参考 {@link com.such.kit.validate.validator.impl.UnemptyValidator}] */
	public static final String VALIDATOR_UNEMPTY = "com.such.kit.validate.validator.impl.UnemptyValidator";
	/** VALIDATOR_EQ：[参考 {@link com.such.kit.validate.validator.impl.EqValidator}] */
	public static final String VALIDATOR_EQ = "com.such.kit.validate.validator.impl.EqValidator";
	/** VALIDATOR_NE：[参考 {@link com.such.kit.validate.validator.impl.NeValidator}] */
	public static final String VALIDATOR_NE = "com.such.kit.validate.validator.impl.NeValidator";
	/** VALIDATOR_LT：[参考 {@link com.such.kit.validate.validator.impl.LtValidator}] */
	public static final String VALIDATOR_LT = "com.such.kit.validate.validator.impl.LtValidator";
	/** VALIDATOR_LE：[参考 {@link com.such.kit.validate.validator.impl.LeValidator}] */
	public static final String VALIDATOR_LE = "com.such.kit.validate.validator.impl.LeValidator";
	/** VALIDATOR_GT：[参考 {@link com.such.kit.validate.validator.impl.GtValidator}] */
	public static final String VALIDATOR_GT = "com.such.kit.validate.validator.impl.GtValidator";
	/** VALIDATOR_GE：[参考 {@link com.such.kit.validate.validator.impl.GeValidator}] */
	public static final String VALIDATOR_GE = "com.such.kit.validate.validator.impl.GeValidator";
	/** VALIDATOR_NUMBER：[参考 {@link com.such.kit.validate.validator.impl.NumberValidator}] */
	public static final String VALIDATOR_NUMBER = "com.such.kit.validate.validator.impl.NumberValidator";
	/** VALIDATOR_DATE：[参考 {@link com.such.kit.validate.validator.impl.DateValidator}] */
	public static final String VALIDATOR_DATE = "com.such.kit.validate.validator.impl.DateValidator";
	/** VALIDATOR_REGULAR：[参考 {@link com.such.kit.validate.validator.impl.RegularValidator}] */
	public static final String VALIDATOR_REGULAR = "com.such.kit.validate.validator.impl.RegularValidator";

	private static String validatorCache = CacheCommons.buildCacheName(Validator.class);

	/**
	 * <pre>
	 * 判断对象是否为空
	 * 此方法支持大部分常用对象、数据结构的空判断
	 * 在非严格验证模式先只会检查是否为 null
	 * 不同类型的对象在严格验证模式下的检验规则如下
	 *   Object [null]
	 *   String [null | "" | "null"  | "NULL" | rule]
	 *   Number [null | rule]
	 *   Array [null | length = 0]
	 *   Collection [null | size() = 0]
	 *   Map [null | size() = 0]
	 * </pre>
	 * @param obj 需验证的对象
	 * @param stringent 是否使用严格验证 [true 是 | false 否]
	 * @param rule 严格验证模式下的附加规则，支持正则表达式 [可空]
	 * @return 是否为空 [true 空 | false 非空]
	 */
	public static boolean isEmpty(Object obj, boolean stringent, String rule) {
		if (obj == null) {
			return true;
		}
		if (stringent) {
			Class<?> clazz = obj.getClass();
			if (clazz.isArray()) {
				if (Array.getLength(obj) == 0) {
					return true;
				} else {
					return false;
				}
			}
			try {
				if (String.class.equals(clazz)) {
					String str = obj.toString();
					str = str.trim();
					if (str.isEmpty()) {
						return true;
					}
					if ("null".equals(str.toLowerCase())) {
						return true;
					}
					if (rule != null)  {
						if (Pattern.matches(rule, obj.toString())) {
							return true;
						}
					}
				} else {
					Class<?> rootClass = getRootClass(clazz);
					if (Number.class.equals(rootClass)) {
						if (rule != null)  {
							if (Pattern.matches(rule, obj.toString())) {
								return true;
							}
						}
					} else {
						Method method = null;
						if (method == null) {
							try {
								method = clazz.getMethod("size");
							} catch (NoSuchMethodException e) {
								Logger.trace(ValidateCommons.class, "未找到 size 方法", e);
							}
						}
						if (method == null) {
							try {
								method = clazz.getMethod("length");
							} catch (NoSuchMethodException e) {
								Logger.trace(ValidateCommons.class, "未找到 length 方法", e);
							}
						}
						if (method == null) {
							return false;
						} else {
							method.setAccessible(true);
							String value = String.valueOf(method.invoke(obj));
							if (Integer.valueOf(value) == 0) {
								return true;
							}
						}
					}
				}
			} catch (Exception e) {
				Logger.warn(ValidateCommons.class, "判断对象是否为空异常", e);
				return false;
			}
		}
		return false;
	}

	/**
	 * <pre>
	 * [参考 {@link #isEmpty(Object, boolean, String)}]
	 * 
	 * rule 的值默认为 null
	 * </pre>
	 */
	public static boolean isEmpty(Object obj, boolean stringent) {
		return isEmpty(obj, stringent, null);
	}

	/**
	 * <pre>
	 * [参考 {@link #isEmpty(Object, boolean, String)}]
	 * 
	 * stringent 的值默认为 true，rule 的值默认为 null
	 * </pre>
	 */
	public static boolean isEmpty(Object obj) {
		return isEmpty(obj, true, null);
	}

	/**
	 * <pre>
	 * [参考 {@link #isEmpty(Object, boolean, String)}]
	 * 
	 * {@link #isEmpty(Object, boolean, String)} 的非值
	 * </pre>
	 */
	public static boolean isNotEmpty(Object obj, boolean stringent, String rule) {
		return !isEmpty(obj, stringent, rule);
	}

	/**
	 * <pre>
	 * [参考 {@link #isEmpty(Object, boolean)}]
	 * 
	 * {@link #isEmpty(Object, boolean)} 的非值
	 * </pre>
	 */
	public static boolean isNotEmpty(Object obj, boolean stringent) {
		return isNotEmpty(obj, stringent, null);
	}

	/**
	 * <pre>
	 * [参考 {@link #isEmpty(Object)}]
	 * 
	 * {@link #isEmpty(Object)} 的非值
	 * </pre>
	 */
	public static boolean isNotEmpty(Object obj) {
		return isNotEmpty(obj, true, null);
	}

	/**
	 * <pre>
	 * 根据规则进行正则表达式验证
	 * </pre>
	 * @param str 需验证的字符串
	 * @param rule 正则表达式
	 * @return 是否匹配 [true 匹配 | false 不匹配]
	 */
	public static boolean matchRule(String str, String rule) {
		if (ValidateCommons.isEmpty(str)) {
			return false;
		}
		if (Pattern.matches(rule, str)) {
			return true;
		}
		return false;
	}

	/**
	 * <pre>
	 * 使用校验器执行校验
	 * </pre>
	 * @param validator 校验器 [参考 VALIDATOR_*]
	 * @param value 待校验值
	 * @param params 参数集
	 * @return 校验结果
	 */
	public static VerifyResult validator(final String validator, String value, List<String> params) {
		Validator v = null;
		try {
			v = CacheCommons.get(validatorCache, validator, new Callable<String, Validator>() {
				@Override
				public Validator call(String cacheName) throws Exception {
					try {
						Class<Validator> clazz = BeanCommons.getClass(validator);
						return clazz.newInstance();
					} catch (ClassNotFoundException e) {
						throw new ValidatorNotFoundException(validator);
					} catch (InstantiationException e) {
						throw new VerifyException(e);
					} catch (IllegalAccessException e) {
						throw new VerifyException(e);
					}
				}
			});
		} catch (Exception e) {
			Logger.error(ValidateCommons.class, "创建校验器异常", e);
		}
		if (ValidateCommons.isEmpty(v, false)) {
			return null;
		} else {
			return v.execute(value, params);
		}
	}

	/**
	 * <pre>
	 * 使用校验器执行校验
	 * </pre>
	 * @param validator 校验器 [参考 VALIDATOR_*]
	 * @param value 待校验值
	 * @param params 参数集
	 * @return 校验结果
	 */
	public static VerifyResult validator(final String validator, String value, String... params) {
		if (params == null) {
			params = new String[0];
		}
		return validator(validator, value, Arrays.stream(params).collect(Collectors.toList()));
	}

	/**
	 * <pre>
	 * [参考 {@link #validator(String, String, List)}]
	 * 
	 * paramsJson 为参数集的 JSON 形式
	 * </pre>
	 */
	public static VerifyResult validator(final String validator, String value, String paramsJson) {
		List<String> params = JSON.parseArray(paramsJson, String.class);
		return validator(validator, value, params);
	}

	private static Class<?> getRootClass(Class<?> clazz) {
		String rootClass = Object.class.getName();
		Class<?> superClass = clazz.getSuperclass();
		if (superClass != null) {
			String className = superClass.getName();
			if (!rootClass.equals(className)) {
				clazz = getRootClass(superClass);
			}
		}
		return clazz;
	}

}
